using System;
using System.Data.Objects;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Web;
using Higgs.Web.AtomPub.Configurations;
using Higgs.Web.AtomPub.Models;
using System.Text.RegularExpressions;

namespace Higgs.Web.AtomPub
{
    public class BaseMediaRepository<TBlogContext, TEntry, TCategory, TMediaItem> : IMediaRepository
        where TBlogContext : IBlogContext<TEntry, TCategory, TMediaItem>
        where TEntry : class, IEntry
        where TCategory : class, ICategory
        where TMediaItem : class, IMediaItem
    {
        private TBlogContext DataContext { get; set; }

        public BaseMediaRepository()
        {
            DataContext = Activator.CreateInstance<TBlogContext>();
        }

        public virtual void SaveFile(IMediaItem media, Stream mediaData, HttpContextBase context)
        {
            var setting = AtomPubConfigSection.Current;
            var temp = new byte[mediaData.Length];
            mediaData.Read(temp, 0, (int) mediaData.Length);
            mediaData.Close();

            var storePath = context.Server.MapPath(media.LogicalPath);
            var dirPath = Path.GetDirectoryName(storePath);
            
            if(!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            
            File.WriteAllBytes(storePath, temp);
        }

        public virtual IMediaItem CreateMedia(HttpContextBase context, string mimeType, Stream mediaData, string slug, IIdentity user)
        {
            var now = DateTime.Now;
            var setting = AtomPubConfigSection.Current;
            var mi = Activator.CreateInstance<TMediaItem>();
            mi.FileName = slug.Replace("[", "").Replace("]", "");
            var dirPath = string.Format("~/{0}/{1}/{2}/", setting.Media.StaticPath, now.Year, now.Month);
            var pattern = new Regex("^" + Regex.Escape(mi.FileName) + @"(\(\d+\))?$", RegexOptions.IgnoreCase);
            var count = DataContext.MediaItems
                                            .Where(x => x.LogicalPath.StartsWith(dirPath))
                                            .ToList()
                                            .Count(x => pattern.IsMatch(x.FileName));
            
            if(count > 0)
            {
                count++;
                mi.FileName += "(" + count + ")";
            }

            mi.LogicalPath = dirPath + mi.FileName + "." + setting.Media.AcceptTypes[mimeType].Extension;
            mi.MimeType = mimeType;
            mi.UpdatedDate = now;

            try
            {
                SaveFile(mi, mediaData, context);
                DataContext.MediaItems.AddObject(mi);
                DataContext.SaveChanges();
            }
            catch (Exception)
            {
                var filePath = context.Server.MapPath(mi.LogicalPath);
                
                if(File.Exists(filePath)) File.Delete(filePath);
                throw new Exception("Unable to create new media item.");
            }
            
            return mi;
        }

        public virtual IMediaItem UpdateMedia(HttpContextBase context, Guid id, string mimeType, Stream mediaData, IIdentity user)
        {
            var mi = GetMediaLink(id, user);

            // TODO: Support change other thing like mimetype, filetype,filename,location if it is possible in WLW2011. And don't forget to use old directory.

            SaveFile(mi, mediaData, context);
            DataContext.SaveChanges();

            return mi;
        }

        public virtual IMediaItem GetMediaLink(Guid id, IIdentity user)
        {
            return DataContext.MediaItems.SingleOrDefault(x => x.Id == id);
        }

        public virtual void DeleteMediaLink(Guid id, HttpContextBase context, IIdentity user)
        {
            var mediaItem = GetMediaLink(id, user);
            var filePath = context.Server.MapPath(mediaItem.LogicalPath);
                
            if(File.Exists(filePath)) File.Delete(filePath);
        }
    }
}